/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

#ifndef __dylab_VectorObjContainer_h__
#define __dylab_VectorObjContainer_h__

//===========================================================================================
#include <dylab/utils/containers/LinearObjContainerBase.h>
#include <dylab/utils/containers/VectorContainer.h>
#include <dylab/utils/containers/ObjManagerBase.h>
#include <dylab/utils/types/dynamicCast.h>

//===========================================================================================
namespace dylab {

    /** 
     */   
    template <
        class _ObjectT
    >
    class VectorObjContainer 
        : public ContainerBase<typename VectorContainer<_ObjectT *>::VectorT>
        , public ObjManagerBase
    { 
    private:
        typedef VectorObjContainer<_ObjectT> VectorObjContainerT;
        typedef typename VectorContainer<_ObjectT *>::VectorT STLcontainerT;
        typedef typename LinearObjContainerBase<STLcontainerT> LinearObjContainerBaseT;
        typedef typename STLcontainerT::value_type ObjectPtrT;
    public:        
        /// utility class (RIAA) for walking through all container elements
        class Iterator
            : public LinearObjContainerBaseT::Iterator
        {
        public:
            Iterator(ContainerBaseT & _c)
                : LinearObjContainerBaseT::Iterator(_c)
                    { }
        };
        //-----------------------------------------------------------------------------
    public:
        /// utility class (RIAA) for walking through all container elements
        class ConstIterator
            : public LinearObjContainerBaseT::ConstIterator
        {
        public:
            ConstIterator(const ContainerBaseT & _c)
                : LinearObjContainerBaseT::ConstIterator(_c)
                    { }
        };
        //-----------------------------------------------------------------------------
    public:
        /// scoped reader class
        class Reader
            : public LinearObjContainerBaseT::Reader
        {
        public:
            Reader(const ContainerBaseT & _c)
                : LinearObjContainerBaseT::Reader(_c)
                    { }
            ObjectPtrT operator[] (uint32_t _index)
                    {
                        DYLAB_ASSERT(_index < getCount());
                        return (*mSTLcontainer)[_index];
                    }
            const ObjectPtrT operator[] (uint32_t _index) const
                    {
                        DYLAB_ASSERT_MSGF2(_index < getCount(), "Index %1% out of range %2%.", _index, getCount());
                        return (*mSTLcontainer)[_index];
                    }
        };
        //-----------------------------------------------------------------------------
    public:
        /// scoped writer class
        class Writer
            : public WriterBase
        {
        public:
            Writer(ContainerBaseT & _c)
                : WriterBase(_c)
                    { }
            void resize(uint32_t _minSize)
                    { mSTLcontainer->resize(_minSize); }
            void insertAtEnd(ObjectPtrT _value)
                    { mSTLcontainer->push_back(_value); }
            ObjectPtrT removeEnd()
                    { 
                        if (dynamicCast<VectorObjContainerT>(mContainerBase)->isObjectOwner())
						{
                            delete mSTLcontainer->back();
							mSTLcontainer->pop_back();
							return NULL;
						}
						else
						{
							ObjectPtrT removedObj = mSTLcontainer->back();
							mSTLcontainer->pop_back();
							return removedObj;
						}
                    }
            void removeAll() 
                    { 
                        if (dynamicCast<VectorObjContainerT>(mContainerBase)->isObjectOwner())
                            for (STLcontainerT::iterator it = mSTLcontainer->begin(); it != mSTLcontainer->end(); it++)
                                delete *it;
                        mSTLcontainer->clear();
                    }
            ObjectPtrT & operator[] (uint32_t _index)
                    {
                        DYLAB_ASSERT_MSGF2(_index < mSTLcontainer->size(), "Index %1% out of range %2%.", _index, (uint32_t)mSTLcontainer->size());
                        return (*mSTLcontainer)[_index];
                    }
        };
        //-----------------------------------------------------------------------------

    public:

        VectorObjContainer(bool _objectOwner)
            : ObjManagerBase(_objectOwner)
                { }

        virtual ~VectorObjContainer()
                { removeAll(); }       

        ObjectPtrT & operator[] (uint32_t _index)
                { return Writer(*this)[_index]; }                    

        const ObjectPtrT operator[] (uint32_t _index) const
                { return Reader(*this)[_index]; }                    

        void resize(uint32_t _minSize) 
                { Writer(*this).resize(_minSize); }

        void insertAtEnd(ObjectPtrT _value)
                { Writer(*this).insertAtEnd(_value); }

        ObjectPtrT removeEnd()
                { return Writer(*this).removeEnd(); }

        void removeAll()
                { Writer(*this).removeAll(); }
    };    
}
//===========================================================================================
#endif // __dylab_VectorObjContainer_h__
